package com.twotiger.and.util;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import android.text.TextUtils;

import com.alibaba.fastjson.JSON;

/**
 * 
 * @Description: 加签验签
 * @Author hansc
 * @Date 2015年7月1日 下午2:59:44
 */
public class Signature {
    
    /**
     * 签名算法(验证时使用)
     * @param o 要参与签名的数据对象
     * @param appKey 
     * @return 签名
     * @throws IllegalAccessException
     */
    public static String getSign(Map<String, String> map, String appKey) {
        String result = transAndSort(map);
        result += "key=" + appKey;
        String parm = result;
        LogUtil.info("加密前" + result);
        result = DigestUtils.md5(result).toUpperCase();
        LogUtil.info("=======" + parm + result);
        return result;
    }

    /**
     * 签名算法
     * @param o 要参与签名的数据对象
     * @param appKey 
     * @return 签名
     * @throws IllegalAccessException
     */
    public static String getSign(Map<String, String> map, String appKey, String nonceStr) {
        map.put("nonceStr", nonceStr);
        String result = transAndSort(map);
        result += "key=" + appKey;
        String parm = result;
        LogUtil.info("加密前" + result);
        result = DigestUtils.md5(result).toUpperCase();
        LogUtil.info("=======" + parm + result);
        return result;
    }

    /**
     * 签名算法
     * @param o 要参与签名的数据对象
     * @param appKey 
     * @return 签名
     * @throws IllegalAccessException
     */
    public static String getSign4Obj(Map<String, String> map, String appKey) {
        Map<String, String> toSign = new HashMap<String, String>();
        Iterator<String> keys = map.keySet().iterator();
        while (keys.hasNext()) {
            String key = keys.next();
            Object value = map.get(key);
            if (value instanceof String) {
                toSign.put(key, (String) value);
            } else {
                toSign.put(key, JSON.toJSONString(value));
            }
        }
        String result = transAndSort(toSign);
        result += "key=" + appKey;
        result = DigestUtils.md5(result).toUpperCase();
        return result;
    }

    /**
     * 包装数据
     * 将签名和随机数填充
     * @param parm
     * @param appKey
     * @return
     */
    public static Map<String, String> wrap(HashMap<String, String> parm, String appKey) {
        String sign = getSign4Obj(parm, appKey);
        String nonce = RandomUtils.getRandomNumbersAndLetters(32);
        parm.put("nonceStr", nonce);
        parm.put("sign", sign);
        return parm;
    }

    /**
     * 将map数据按ASCII码从小到大排序（字典序）后使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串
     * 
     * @param map
     * @return
     */
    private static String transAndSort(Map<String, String> map) {
        StringBuilder sb = new StringBuilder();
        map = new TreeMap<String, String>(map);
        Iterator<String> keys = map.keySet().iterator();
        while (keys.hasNext()) {
            String key = keys.next();
            String val = map.get(key);
            if (!StringUtils.isBlank(val)) {
                sb.append(key + "=" + val + "&");
            }
        }
        String result = sb.toString();
        return result;
    }

    /**
     * 验签
     * @param map
     * @param appKey 
     * @return
     */
    public static boolean checkSign(Map<String, String> map, String appKey) {
        LogUtil.info(JSON.toJSONString(map));
        String sign = (String) map.get("sign");
        String nonceStr = (String) map.get("nonceStr");
        if (TextUtils.isEmpty(sign) || TextUtils.isEmpty(nonceStr)) {
            LogUtil.info("API返回的数据签名数据不存在，有可能被第三方篡改!!!");
            return false;
        }
        LogUtil.info("服务器回包里面的签名是:" + sign);
        //清掉返回数据对象里面的Sign数据（不能把这个数据也加进去进行签名），然后用签名算法进行签名
        map.put("sign", "");
        //将API返回的数据根据用签名算法进行计算新的签名，用来跟API返回的签名进行比较
        String signForAPIResponse = Signature.getSign(map, appKey, nonceStr);
        if (!signForAPIResponse.equals(sign)) {
            //签名验不过，表示这个API返回的数据有可能已经被篡改了
            LogUtil.info("API返回的数据签名验证不通过，有可能被第三方篡改!!!");
            return false;
        }
        LogUtil.info("恭喜，API返回的数据签名验证通过!!!");
        return true;
    }
}
